<?php
class CURL
{
	
	const GET = 'get';
	
	const POST = 'post';
	
	/**
	 * Do HTTP GET and return response body
	 * 
	 * @param $url
	 * @param $args
	 * @param $cookies
	 * @param $options
	 * @return string
	 */
	public static function get($url, $args=null, $cookies = null, $options=null, $returnarray = false) {
		
		$result = self::request(self::GET, $url, $args, $cookies, $options);
		if ($returnarray)
			return $result;
		return $result ['body'];
	}
	
	/**
	 * Do HTTP POST and return response body
	 * 
	 * @param $url
	 * @param $args
	 * @param $cookies
	 * @param $options
	 * @return string
	 */
	public static function post($url, $args=null, $cookies = null, $options=null, $returnarray = false) {
		
		$result = self::request(self::POST, $url, $args, $cookies, $options);
		if ($returnarray)
			return $result;
		return $result ['body'];
	}
	
	/**
	 * Do HTTP Request and return response body
	 * 
	 * @param $method
	 * @param $url
	 * @param $args
	 * @param $cookies
	 * @param $options
	 * @return string
	 */
	public static function request($method, $url, $args = null, $cookies = null, $options=null) {
		
		$_options = (array)$options + array(
			CURLOPT_CONNECTTIMEOUT => 5,
			CURLOPT_TIMEOUT => 5,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_HEADER => true
		);
		
		if($cookies != null) {
			$_options[CURLOPT_COOKIE] = self::toCookieHeader($cookies);
		}
		
		switch($method) {
			case self::POST:
				$_options[CURLOPT_URL] = $url;
				$_options[CURLOPT_POST] = true;
				$_options[CURLOPT_POSTFIELDS] = $args;
				break;
			case self::GET:
			default:
				$_options[CURLOPT_URL] = self::toURL($url, $args);
				$_options[CURLOPT_HTTPGET] = true;
				break;
		}
		
		for($i=0;$i<3;$i++) { // retry 3 times
			$ch = curl_init();
			curl_setopt_array($ch, $_options);
			$response = curl_exec($ch);
			$error = curl_error($ch);
			$errno = curl_errno($ch);
			curl_close($ch);
			
			if($response !== false) {
				$cookies = array();$header = array();
				self::fetchCookie($cookies, $response);
				$str = self::fetchHeader($header,$response);
				return array('header' => $header , 'raw' => $str,'cookies'=> $cookies,'body' => self::fetchBody($response));
			}
		}
		
		throw new Exception($error, $errno);
		
	}
	
	/**
	 * 
	 * @param $url
	 * @param $args
	 * @return string
	 */
	private static function toURL($url, $args) {
		
		if($args != null) {
			foreach($args as $k => $v) {
				$args[$k] = urlencode($k)."=".urlencode($v);
			}
			
			$url .= (strstr($url, "?") ? "&" : "?") . join("&", $args);
		}
		
		return $url;
		
	}
	
	/**
	 * 
	 * @param $cookies
	 * @return string
	 */
	private static function toCookieHeader($cookies) {
		$_cookies = array();
		foreach($cookies as $k=>$v)
			$_cookies[] = $k."=".($v);
		
		return join("; ", $_cookies);
	}
	
	/**
	 * 
	 * @param $cookies
	 * @param $headers
	 * @return void
	 */
	private static function fetchCookie(&$cookies, $headers) {
		
		if(preg_match_all("/Set-Cookie: ([^=;]+)=([^=;]+)/i", $headers, $matches)) {
			for($i=0;$i<count($matches[1]);$i++) {
				$cookies[$matches[1][$i]] = $matches[2][$i];
			}
		}
		
	}
	
	private static function fetchHeader(&$header,$response) {
		$headers = explode("\r\n\r\n",$response);
		$a = explode("\r\n",$headers[0]);
		$c = count($a);
		if ($c > 0) {
			$b = explode(' ',$a[0]);
			$header['protocol'] = $b[0];
			$header['status'] = $b[1];
			$header['response'] = $a[0];
			for($i = 1 ; $i < $c; ++$i) {
				$b = explode(':',$a[$i]);
				$k = $b[0];
				unset($b[0]);
				$v = implode(':',$b);
				if ($k == 'Set-Cookie') {
					$header[$k][] = trim($v);
				} else {
					$header[$k] = trim($v);
				}
			}
		}
		return $headers[0];
	}
	
	/**
	 * 
	 * @param $response
	 * @return string
	 */
	private static function fetchBody($response) {
		
		if($response != null) {
			$_response = explode("\r\n\r\n", $response);
			
			for($i=0;$i<count($_response);$i++) {
				if(strpos($_response[$i], "HTTP/") === 0) {
					unset($_response[$i]);
				} else {
					break;
				}
			}
			
			return join("\r\n\r\n", $_response);
		} else {
			return null;
		}
		
	}
	
}
?>